home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / quartz / quartz10.lha / src / presto / scheduler_sig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-02  |  8.1 KB  |  309 lines

  1. /*
  2.  * Signal handling nonsense.  Signals need to be dealt with in their
  3.  * own class.  Suggestions anyone?
  4.  *
  5.  * Main chore here is to catch all nasty signals in the parent so we can kill
  6.  * off all the children processes so they don't loop forever.  (if the parent
  7.  * dies while "busy", he never gets unbusy) We can't protect against
  8.  * noncatchable signals in the parent, specificall SIGKILL.  The best we can do
  9.  * is in the children, check every once in a while if the current ppid is not
  10.  * init.  Really need a SIGPARENT  (SIGPARNT?) to notify the children that its
  11.  * parent has changed.
  12.  *
  13.  * Last modified:
  14.  *            bnb 
  15.  *            1/27/88 to create
  16.  */
  17.  
  18.  
  19. #include <sys/types.h>
  20. #include <sys/wait.h>
  21. #include <signal.h>
  22. #include <osfcn.h>
  23. #include "presto.h"
  24.  
  25.  
  26. //
  27. // Route all normal default signals through the parent handler.  Children
  28. // should not be handling signals other than those WHICH are defined
  29. // by presto.  The whole idea of signals in this environment is strange.
  30. // Signals are for processes.  Signals should be for threads.
  31. //
  32.  
  33.  
  34. typedef int    (*PFSigHandler)(int, int, sigcontext*);
  35. int    schedulerSigHandler(int sig, int code, struct sigcontext *scp);
  36. int    schedulerReapChild(int sig, int code, struct sigcontext *scp);
  37.  
  38. #ifdef sequent
  39. static  struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),1};
  40. static  struct sigvec CHLD_vec = {schedulerReapChild, 0, 1};
  41. #endif sequent
  42. #ifdef sun
  43. static  struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
  44. static  struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
  45. #endif sun
  46. #ifdef vax
  47. static  struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
  48. static  struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
  49. #endif vax
  50.  
  51. // default handler
  52. static struct sigvec DFL_vec = {(PFSigHandler)SIG_DFL, 0, 0};
  53.  
  54.  // force kernel sigvec  to be called
  55. #ifdef sequent
  56. #define SIGVEC_OS    _sigvec
  57. #endif sequent
  58.  
  59. #ifdef sun
  60. #define SIGVEC_OS    sigvec
  61. #endif sun
  62.  
  63. #ifdef vax
  64. #define SIGVEC_OS    sigvec
  65. #endif vax
  66.  
  67. extern int SIGVEC_OS(int, struct sigvec*, struct sigvec*);
  68.  
  69. //
  70. // Force the parent to come through here on all signals that
  71. // are "unpleasant" and not already handled.
  72. //
  73. void
  74. Scheduler::initsighandlers(int setupdefaults)
  75. {
  76.     struct sigvec sv;
  77.     int sig;
  78.  
  79.     if (setupdefaults == 0) {
  80.         SIGVEC_OS(SIGCHLD, &CHLD_vec, (struct sigvec*)0);
  81.         return;
  82.     } else if (setupdefaults < 0) {
  83.         /*
  84.          * Don't be bothered by exiting children.
  85.          */
  86.         SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);    
  87.         return;
  88.     }
  89.  
  90.     for (sig = 1; sig < NSIG; sig++)    {
  91.         switch (sig) {
  92.         case    SIGSTOP:
  93.         case    SIGTSTP:
  94.         case    SIGTTIN:
  95.         case    SIGTTOU:
  96.         case    SIGURG:
  97.         case    SIGCONT:
  98.         case    SIGIO:
  99.         case    SIGCHLD:
  100.         case    SIGWINCH:
  101.             continue;
  102.         default:
  103.             if (SIGVEC_OS(sig, 0, &sv) < 0)
  104.                 continue;     // might make some noise
  105.             if (sv.sv_handler != (PFSigHandler)SIG_DFL)
  106.                 continue;
  107.             (void) SIGVEC_OS(sig, &HAND_vec, (struct sigvec *)0);
  108.         }
  109.     }
  110. }
  111.  
  112. //
  113. // Parent proc comes here when it is time to kill everyone off.
  114. // We do not necessarily get a core dump and we do not terminate
  115. // ourselves.  The caller must do that.  We just kill off everybody else.
  116. //
  117. // if sig is negative, then we are not the parent, but a child proc
  118. // who says KILL EVERYONE and forgewt about  being polite.  Child procs
  119. // should use this when they detect that their parent is dead, but
  120. // realize that everyone else must die also.  If the root proc does this,
  121. // nobody will be cleaned up after, but it would still work.
  122. //
  123. // Killer siblings can end up killing one another more than they need
  124. // too, since we don't bother to mark thisproc as reaped before it
  125. // nukes itself.  It doesn't matter, in the worst case, some guys get killed
  126. // more than once.
  127. //
  128. void
  129. Scheduler::abort(int sig)
  130. {
  131.     int pnum;                // proc num of dying proc
  132.     int tpid;                // pid of dying proc
  133.     union wait status;            // and how they died
  134.     int    waitforchild = 1;        // presume we are parent
  135.  
  136.     if (sig < 0)    {
  137.         sig = -sig;
  138.         waitforchild = 0;
  139.     } else    {
  140.         if (thisproc != sc_p_procs[0]) {    // non root proc
  141.             kill(thisproc->pid(), sig);    // just dies, parent
  142.         }                    // should clean up
  143.         //
  144.         // only root process gets this far
  145.         //
  146.         // no interruptions please
  147.         SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);    
  148.     }
  149.     for (pnum = 0; pnum < sc_p_numschedulers; pnum++)    {
  150.         Process *p = sc_p_procs[pnum];
  151.  
  152.         if (p == thisproc)        // we've got a JOB to do!
  153.             continue;
  154.  
  155.         if (waitforchild && p->state()&S_REAPED)// not sibling killer
  156.             continue;            // and already reaped
  157.  
  158.         //
  159.         // Could either pass sig along to all children, in which
  160.         // case we might end up with tons of core files, or
  161.         // just say "to hell with it", one core file is enough.
  162.         // All we care about here is that everybody else stops
  163.         //
  164.  
  165.         while (kill( p->pid(), SIGKILL) == 0)
  166.             continue;    // force him to die
  167.  
  168.         if (waitforchild == 0)    // can't reap sibling
  169.             continue;
  170.  
  171.         //
  172.         // pick up dead procs.  Deal with the chance that
  173.         // multiple guys may die while we are doing this
  174.         //
  175.         do {
  176.             tpid = wait((int*)(&status));
  177.             if (tpid >= 0)    {
  178.                 int procnum = pidtoprocnum(tpid);
  179.                 if (procnum >= 0)
  180.                     sc_p_procs[procnum]->setstate(S_REAPED);
  181.                 if (status.w_coredump)
  182.                     storecore(pidtoprocnum(tpid));
  183.             }
  184.         } while (tpid != p->pid() && tpid >= 0);
  185.     }
  186.     //
  187.     // You may see this message more than once.  Can't lock though
  188.     // cuz we could get killed in the lock, and then nobody else
  189.     // could proceed.  
  190.     //
  191.     if (waitforchild == 0)
  192.         cerr << "Sibling ";
  193.     cerr << "Scheduler aborting with signal " << sig << "\n";
  194.     (void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
  195.     (void)kill(thisproc->pid(), sig);
  196.     // NOT REACHED (definitely)        
  197. }
  198.  
  199. //
  200. // Write a core file.  Hope we get to move it before someone else
  201. // dumps.  The first core file that dumps is called simply "core.First",
  202. // all the rest are appended with the number of the processor
  203. // that dumped.
  204. // If you end up with a core.-1 file, then something bizarre happened to the
  205. // pid to procnum mapping function and you may be missing some core files.
  206. // As they say in te compouter business "This should never happen."
  207. //
  208.  
  209. void
  210. Scheduler::storecore(int pnum)                             
  211. {
  212.     int rename(char*, char*);
  213.     static int firstdump = 1;
  214.     char cname[16];
  215.  
  216.     if (firstdump)    {
  217.         sprintf(cname,"core.First");
  218.         firstdump = 0;
  219.     } else    {
  220.         sprintf(cname,"core.%d", pnum);
  221.     }
  222.     cerr << "Caught core file " << (char*)&cname[0] << "\n";
  223.     (void)rename("core", cname);
  224. }
  225.  
  226. int
  227. Scheduler::pidtoprocnum(int pid)
  228. {
  229.     int p;
  230.     for (p = 0; p < sc_p_numschedulers; p++)
  231.         if (pid == sc_p_procs[p]->pid())
  232.             return p;    // presto pid
  233.     return -1;
  234. }
  235.  
  236.  
  237. //
  238. // SIGCHLD handler.  If we are the root proc, clean up the child, abort
  239. // everyone else with the a clean signal.  We never return from 
  240. // schedulerSigHandler
  241. // unless we are already handloing some kind of a terminating signal.
  242. //
  243. int
  244. schedulerReapChild(int sig, int code, struct sigcontext *scp)
  245. {
  246.     union wait status;
  247.     int tpid;
  248.     int procnum;
  249.     int wait3(union wait*, int, int);
  250.  
  251.     if (sched == 0)
  252.         return 0;        //???
  253.     if (thisproc != sched->sc_p_procs[0])    
  254.         return 0;    // who else and why would would it be caught?
  255.  
  256.     tpid = wait3(&status, WNOHANG|WUNTRACED, 0);
  257.  
  258.     if (tpid <= 0)
  259.         return 0 ;        // spurious?
  260.     if (WIFSTOPPED(status))        // child could pause
  261.         return 0;
  262.  
  263.     cerr << "Process " << tpid ;    
  264.     if (WIFSIGNALED(status))    {
  265.         procnum = sched->pidtoprocnum(tpid);
  266.         if (procnum >= 0)
  267.             sched->sc_p_procs[procnum]->setstate(S_REAPED);
  268.  
  269.         if (status.w_coredump)
  270.             sched->storecore(procnum);
  271.         cerr <<  " killed " << status.w_termsig  << "\n";
  272.     } else        // must have just exited
  273.         cerr << " exited " << status.w_termsig << "\n";
  274.     //
  275.     // don't bother to core dump everyone else
  276.     //
  277.     schedulerSigHandler(SIGKILL, code, scp);
  278.     //
  279.     //     NOT REACHED  (well... maybe)
  280.     //
  281.     sig=sig;
  282.     return 0;
  283. }
  284.  
  285. //
  286. //
  287. // parent comes here when we get a "default" signal
  288. //
  289. int 
  290. schedulerSigHandler(int sig, int code, struct sigcontext *scp)
  291. {    
  292.     static int aborting = 0;        // avoid looping on signals
  293.     if (sched)        {        // once the axe is in motion
  294.         if (aborting == 0)    {
  295.             aborting++;
  296.             sched->abort(sig);
  297.             // NOT REACHED
  298.         } else
  299.             return 0;
  300.     } else    {
  301.         // sig ourselves
  302.         (void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
  303.         (void)kill(getpid(), sig);
  304.         // NOT REACHED
  305.     }
  306.     code=code;scp=scp;
  307.     return 0;
  308. }
  309.